use chrono::NaiveDateTime;
use sea_orm::{
    ActiveModelTrait, ColumnTrait, DbConn, DbErr, DerivePartialModel, EntityTrait, FromQueryResult,
    ModelTrait, PaginatorTrait, PartialModelTrait, QueryFilter, QueryOrder, QueryTrait, Set,
};
use serde::{Deserialize, Serialize};
use validator::Validate;

use crate::entity::sys_dict_data::Entity as SysDictData;
use crate::entity::sys_dict_type::Entity as SysDictType;
use crate::entity::{sys_dict_data, sys_dict_type};
use crate::util::current_datetime;
use crate::{model_fetch, model_list};

pub struct SysDict;

#[derive(Debug, DerivePartialModel, FromQueryResult, Serialize)]
#[sea_orm(entity = "SysDictType")]
pub struct SysDictVo {
    pub id: i32,
    pub dict_name: String,
    pub dict_type: String,
    pub status: bool,
    pub remark: String,
    pub created_at: NaiveDateTime,
}

impl From<sys_dict_type::Model> for SysDictVo {
    fn from(value: sys_dict_type::Model) -> Self {
        Self {
            id: value.id,
            dict_name: value.dict_name,
            dict_type: value.dict_type,
            status: value.status,
            remark: value.remark,
            created_at: value.created_at,
        }
    }
}

/// 创建和修改[sys_dict_type]提交的数据
#[derive(Debug, Deserialize, Validate)]
pub struct SysDictDo {
    #[validate(length(min = 3, max = 32))]
    pub dict_name: String,
    #[validate(length(min = 3, max = 32), non_control_character)]
    pub dict_type: String,
    #[serde(default)]
    pub status: bool,
    #[validate(length(max = 255))]
    #[serde(default)]
    pub remark: String,
}

impl Into<sys_dict_type::ActiveModel> for SysDictDo {
    fn into(self) -> sys_dict_type::ActiveModel {
        sys_dict_type::ActiveModel {
            dict_name: Set(self.dict_name),
            dict_type: Set(self.dict_type),
            status: Set(self.status),
            remark: Set(self.remark),
            updated_at: Set(current_datetime()),
            ..Default::default()
        }
    }
}

#[derive(Debug, DerivePartialModel, FromQueryResult, Serialize)]
#[sea_orm(entity = "SysDictData")]
pub struct SysDictDataVo {
    pub id: i32,
    pub dict_type: String,
    pub dict_code: String,
    pub dict_value: String,
    pub dict_sort: i8,
    pub status: bool,
    pub created_at: NaiveDateTime,
}

#[derive(Debug, DerivePartialModel, FromQueryResult, Serialize)]
#[sea_orm(entity = "SysDictData")]
pub struct SysDictDataSimpleVo {
    pub dict_code: String,
    pub dict_value: String,
}

impl From<sys_dict_data::Model> for SysDictDataVo {
    fn from(value: sys_dict_data::Model) -> Self {
        Self {
            id: value.id,
            dict_type: value.dict_type,
            dict_code: value.dict_code,
            dict_value: value.dict_value,
            dict_sort: value.dict_sort,
            status: value.status,
            created_at: value.created_at,
        }
    }
}

/// 创建和修改[sys_dict_data]提交的数据
#[derive(Debug, Deserialize, Validate)]
pub struct SysDictDataDo {
    #[validate(length(min = 3, max = 32), non_control_character)]
    pub dict_type: String,
    #[validate(length(min = 1, max = 32), non_control_character)]
    pub dict_code: String,
    #[validate(length(min = 1, max = 32))]
    pub dict_value: String,
    pub dict_sort: i8,
    #[serde(default)]
    pub status: bool,
}

impl Into<sys_dict_data::ActiveModel> for SysDictDataDo {
    fn into(self) -> sys_dict_data::ActiveModel {
        sys_dict_data::ActiveModel {
            dict_code: Set(self.dict_code),
            dict_type: Set(self.dict_type),
            dict_value: Set(self.dict_value),
            dict_sort: Set(self.dict_sort),
            status: Set(self.status),
            updated_at: Set(current_datetime()),
            ..Default::default()
        }
    }
}

#[allow(unused)]
impl SysDict {
    model_list!(
        #[model = sys_dict_type]
        #[filter = []]
        /// 分页列出[sys_dict_type]
        pub fn list_type()
    );

    model_fetch!(
        #[model=sys_dict_type]
        /// 通过id获取[sys_dict_type]
        pub fn fetch_dict(Id:eq:id:i32, Id:eq:id1:i32=>opt)
    );

    model_fetch!(
        #[model=sys_dict_type]
        /// 通过type获取[sys_dict_type]
        pub fn fetch_dict_type(DictType:eq:data_type:String, Status:eq:status:bool=>opt)
    );

    /// 创建[sys_dict_type]
    pub async fn create_type(db: &DbConn, data: SysDictDo, operator: i32) -> Result<(), DbErr> {
        let mut data: sys_dict_type::ActiveModel = data.into();
        data.created_at = Set(current_datetime());
        data.created_by = Set(operator);
        data.updated_by = Set(operator);
        data.insert(db).await.map(|_| ())
    }

    /// 更新[sys_dict_type], 当id不存在时, 抛出错误
    pub async fn update_type(
        db: &DbConn,
        id: i32,
        data: SysDictDo,
        operator: i32,
    ) -> Result<(), DbErr> {
        let mut data: sys_dict_type::ActiveModel = data.into();
        data.id = Set(id);
        data.updated_by = Set(operator);
        data.update(db).await.map(|_| ())
    }

    /// 删除[sys_dict_type], 当id不存在时, 抛出错误
    pub async fn delete_type(db: &DbConn, id: i32) -> Result<bool, DbErr> {
        let model = sys_dict_type::Entity::find_by_id(id).one(db).await?;
        if let Some(model) = model {
            sys_dict_data::Entity::delete_many()
                .filter(sys_dict_data::Column::DictType.eq(&model.dict_type))
                .exec(db)
                .await?;
            model.delete(db).await.map(|r| r.rows_affected > 0)
        } else {
            Ok(true)
        }
    }

    model_list! {
        #[model=sys_dict_data]
        #[order=[DictSort:Asc]]
        /// 分页列出[sys_dict_data]
        pub fn list_dict_data(DictType:eq:dict_type:String,Status:eq:status:bool=>opt)
    }

    /// 创建[sys_dict_data]
    pub async fn create_dict_data<D>(
        db: &DbConn,
        data: SysDictDataDo,
        operator: i32,
    ) -> Result<D, DbErr>
    where
        D: From<sys_dict_data::Model>,
    {
        let mut data: sys_dict_data::ActiveModel = data.into();
        data.created_at = Set(current_datetime());
        data.created_by = Set(operator);
        data.updated_by = Set(operator);
        data.insert(db).await.map(From::from)
    }

    /// 更新[sys_dict_data], 当id不存在时, 抛出错误
    pub async fn update_dict_data<D>(
        db: &DbConn,
        id: i32,
        data: SysDictDataDo,
        operator: i32,
    ) -> Result<D, DbErr>
    where
        D: From<sys_dict_data::Model>,
    {
        let mut data: sys_dict_data::ActiveModel = data.into();
        data.id = Set(id);
        data.updated_by = Set(operator);
        data.update(db).await.map(From::from)
    }

    /// 删除[sys_dict_data], 当id不存在时, 抛出错误
    pub async fn delete_dict_data(db: &DbConn, id: i32) -> Result<bool, DbErr> {
        sys_dict_data::ActiveModel {
            id: Set(id),
            ..Default::default()
        }
        .delete(db)
        .await
        .map(|r| r.rows_affected > 0)
    }
}
